package com.xhwl.logistics.config;

import com.xhwl.logistics.bo.redis.VehicleTokenBO;
import com.xhwl.logistics.config.context.YamlSourceLoadFactory;
import com.xhwl.logistics.converter.mapstruct.CentBiConverter;
import com.xhwl.logistics.converter.mapstruct.CentProjectConverter;
import com.xhwl.logistics.converter.mapstruct.VehicleAccessRecordConverter;
import com.xhwl.logistics.converter.mapstruct.VehicleBlacklistConverter;
import com.xhwl.logistics.converter.mapstruct.VehicleCarConverter;
import com.xhwl.logistics.converter.mapstruct.VehicleCarportConverter;
import com.xhwl.logistics.converter.mapstruct.VehicleIntegratedConfigConverter;
import com.xhwl.logistics.converter.mapstruct.VehicleParkingLotConverter;
import com.xhwl.logistics.converter.mapstruct.VehiclePassageConverter;
import com.xhwl.logistics.converter.mapstruct.VehiclePayRecordConverter;
import com.xhwl.logistics.converter.mapstruct.VehicleSyncConverter;
import org.mapstruct.factory.Mappers;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.hash.Jackson2HashMapper;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.client.RestTemplate;

@Configuration
@PropertySource(value = {"classpath:/vehicle-config/home-address.yml", "classpath:/vehicle-config/vehicle-config.yml"}, factory = YamlSourceLoadFactory.class)
public class VehicleConfig {

//    @Bean
//    public Retrofit retrofit() {
//        return new Retrofit.Builder()
//                .addConverterFactory(GsonConverterFactory.create())
//                .build();
//    }

    //MapStruct的依赖注入可以改用MapStruct的自带的依赖注入功能，而不需要自己手动Mappers.getMapper然后注入
    private static class MapStructConverter {
        @Bean
        public VehicleBlacklistConverter vehicleBlacklistConverter() {
            return Mappers.getMapper(VehicleBlacklistConverter.class);
        }
        @Bean
        public VehicleIntegratedConfigConverter vehicleIntegratedConfigConverter() {
            return Mappers.getMapper(VehicleIntegratedConfigConverter.class);
        }
        @Bean
        public VehicleSyncConverter vehicleSyncConverter() {
            return Mappers.getMapper(VehicleSyncConverter.class);
        }
        @Bean
        public VehiclePassageConverter vehiclePassageConverter() {
            return Mappers.getMapper(VehiclePassageConverter.class);
        }
        @Bean
        public CentProjectConverter centProjectConverter() {
            return Mappers.getMapper(CentProjectConverter.class);
        }
        @Bean
        public VehicleAccessRecordConverter vehicleAccessRecordConverter() {
            return Mappers.getMapper(VehicleAccessRecordConverter.class);
        }
        @Bean
        public VehicleCarportConverter vehicleCarportConverter() {
            return Mappers.getMapper(VehicleCarportConverter.class);
        }
        @Bean
        public VehicleParkingLotConverter vehicleParkingLotConverter() {
            return Mappers.getMapper(VehicleParkingLotConverter.class);
        }
        @Bean
        public VehicleCarConverter vehicleCarConverter() {
            return Mappers.getMapper(VehicleCarConverter.class);
        }
        @Bean
        public CentBiConverter centBiConverter() {
            return Mappers.getMapper(CentBiConverter.class);
        }
        @Bean
        public VehiclePayRecordConverter vehiclePayRecordConverter() {
            return Mappers.getMapper(VehiclePayRecordConverter.class);
        }
    }

    private static class ThreadPoolConfig {
        @Bean
        public ThreadPoolTaskExecutor threadPoolTaskExecutorForSchedule() {
            ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
            threadPoolTaskExecutor.setCorePoolSize(16);
            threadPoolTaskExecutor.setMaxPoolSize(32);
            threadPoolTaskExecutor.setKeepAliveSeconds(60);
            threadPoolTaskExecutor.setQueueCapacity(1000);
            threadPoolTaskExecutor.setThreadNamePrefix("Vehicle-Schedule-");
            threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
            return threadPoolTaskExecutor;
        }
        @Bean
        public ThreadPoolTaskExecutor threadPoolTaskExecutorForLog() {
            ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
            threadPoolTaskExecutor.setCorePoolSize(16);
            threadPoolTaskExecutor.setMaxPoolSize(32);
            threadPoolTaskExecutor.setKeepAliveSeconds(60);
            threadPoolTaskExecutor.setQueueCapacity(1000);
            threadPoolTaskExecutor.setThreadNamePrefix("Vehicle-Log-");
            threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
            return threadPoolTaskExecutor;
        }
        @Bean
        public ThreadPoolTaskExecutor threadPoolTaskExecutorForAlarm() {
            ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
            threadPoolTaskExecutor.setCorePoolSize(16);
            threadPoolTaskExecutor.setMaxPoolSize(32);
            threadPoolTaskExecutor.setKeepAliveSeconds(60);
            threadPoolTaskExecutor.setQueueCapacity(1000);
            threadPoolTaskExecutor.setThreadNamePrefix("Vehicle-Alarm-");
            threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
            return threadPoolTaskExecutor;
        }
    }

    private static class HttpConfig {
        @Bean
        public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
            return restTemplateBuilder.build();
        }
    }

    private static class RedisConfig {
        @Bean
        public GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer() {
            return new GenericJackson2JsonRedisSerializer();
        }
        @Bean
        public Jackson2HashMapper jackson2HashMapper() {
            return new Jackson2HashMapper(false);
        }
        @Bean
        public RedisTemplate<String, VehicleTokenBO> redisTemplateForVehicleToken(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, VehicleTokenBO> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);
            redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer());
            redisTemplate.setHashKeySerializer(StringRedisSerializer.UTF_8);
            redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer());
            return redisTemplate;
        }
        @Bean
        public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, Object> redisTemplateForObject = new RedisTemplate<>();
            redisTemplateForObject.setConnectionFactory(redisConnectionFactory);
            redisTemplateForObject.setKeySerializer(StringRedisSerializer.UTF_8);
            redisTemplateForObject.setValueSerializer(genericJackson2JsonRedisSerializer());
            redisTemplateForObject.setHashKeySerializer(StringRedisSerializer.UTF_8);
            redisTemplateForObject.setHashValueSerializer(genericJackson2JsonRedisSerializer());
            return redisTemplateForObject;
        }
    }

}
